package net.linku.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.linku.annotation.ChangeRecordEnums;
import net.linku.annotation.ChangeRecordLog;
import net.linku.annotation.change.service.IChangeService;
import net.linku.constant.Constants;
import net.linku.converter.RoleMapperConverter;
import net.linku.domain.LAAccountRole;
import net.linku.domain.LARole;
import net.linku.enums.ErrorMessageEnums;
import net.linku.exception.LinkUException;
import net.linku.model.req.login.UserRequestParams;
import net.linku.model.req.menu.AdminRoleQuery;
import net.linku.model.req.privilege.AdminStatusChangeReq;
import net.linku.model.req.role.AdminRoleReq;
import net.linku.model.req.role.AdminRoleReqQuery;
import net.linku.model.resp.login.LARoleVO;
import net.linku.repository.LAAccountRoleRepository;
import net.linku.repository.LARoleRepository;
import net.linku.service.LARoleService;
import net.linku.utils.TenantContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * LARoleServiceImpl 实现了 LARoleService 接口，
 * 提供了与用户角色相关的业务逻辑。
 * <p>
 * 该类主要用于实现超级管理员判断的方法。
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LARoleServiceImpl implements IChangeService<LARole>, LARoleService {

    private final LARoleRepository laRoleRepository;
    private final LAAccountRoleRepository accountRoleRepository;
    private final TransactionTemplate transactionTemplate;
    private final MessageSource messageSource;

    /**
     * 判断用户是否为超级管理员。
     *
     * @param userRequestParams 用户构建信息
     * @return 如果用户是超级管理员，返回 true；否则返回 false。
     */
    @Override
    public Boolean isSuperAdmin(UserRequestParams userRequestParams) {
        // 创建包含用户ID的查询条件对象
        AdminRoleQuery adminRoleQuery = AdminRoleQuery.builder()
                .accountIds(Collections.singletonList(userRequestParams.getUserId()))
                .tenantId(Long.valueOf(userRequestParams.getTenantId()))
                .build();

        // 获取用户角色代码
        String roleCode = laRoleRepository.getUserRoleCode(adminRoleQuery);

        // 判断角色代码是否为超级管理员角色代码
        if (StringUtils.isNotEmpty(roleCode) && Constants.ROLE_ADMIN.equals(roleCode)) {
            return true;
        }
        return false;
    }

    /**
     * 根据账户和租户id查询用户的角色信息
     *
     * @param userRequestParams 用户请求参数，包含租户ID和用户ID。
     * @return 符合条件的 LARole 列表。
     */
    @Override
    public List<LARole> getRolesByAccountId(UserRequestParams userRequestParams) {
        // 创建包含用户ID和租户ID的查询条件对象
        AdminRoleQuery adminRoleQuery = AdminRoleQuery.builder()
                .accountIds(Collections.singletonList(userRequestParams.getUserId()))
                .tenantId(Long.valueOf(userRequestParams.getTenantId()))
                .build();

        // 查询账户对应的用户角色id集合
        List<LAAccountRole> laAccountRoles = accountRoleRepository.queryRoleIdsByCondition(adminRoleQuery);

        // 提取角色ID列表
        List<Long> roleIds = laAccountRoles.stream()
                .map(LAAccountRole::getRoleId)
                .collect(Collectors.toList());

        // 如果角色ID列表为空，则返回空列表
        if (roleIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 根据角色ID列表和其他条件查询角色
        adminRoleQuery.setRoleIds(roleIds);
        return laRoleRepository.queryRolesByCondition(adminRoleQuery);
    }

    /**
     * 分页查询角色列表
     *
     * @param query 分页查询条件
     * @return 分页结果
     */
    @Override
    public Page<LARoleVO> pageRoles(AdminRoleReqQuery query) {
        // 执行分页查询
        Page<LARole> roles = laRoleRepository.pageRoles(query);

        // 将分页结果转换为 LARoleVO 对象
        return RoleMapperConverter.INSTANCE.covertToPageRoleVO(roles);
    }

    /**
     * 添加角色
     *
     * @param roleReq 角色请求对象
     * @return 添加结果
     */
    @Override
    @ChangeRecordLog(serviceclass = LARoleServiceImpl.class,
            businessType = ChangeRecordEnums.TYPE.ADMIN_ROLE,
            action = ChangeRecordEnums.ACTION.INSERT,
            param = "#roleReq.id",
            changeType = ChangeRecordEnums.CHANGE_TYPE.INSERT,
            desc = "新建角色数据"
    )
    public Boolean addRole(AdminRoleReq roleReq) {
        return roleInfoSaveOrUpdate(roleReq);
    }

    /**
     * 更新角色
     *
     * @param roleReq 角色请求对象
     * @return 更新结果
     */
    @Override
    @ChangeRecordLog(serviceclass = LARoleServiceImpl.class,
            businessType = ChangeRecordEnums.TYPE.ADMIN_ROLE,
            action = ChangeRecordEnums.ACTION.MODIFY,
            param = "#roleReq.id",
            changeType = ChangeRecordEnums.CHANGE_TYPE.MODIFY,
            desc = "修改角色数据"
    )
    public Boolean updateRole(AdminRoleReq roleReq) {
        Assert.notNull(roleReq.getId(), "角色ID不能为空");
        return roleInfoSaveOrUpdate(roleReq);
    }

    /**
     * 删除角色
     *
     * @param statusChangeReq 角色状态变更请求对象
     * @return 删除结果
     */
    @Override
    public Boolean deleteRole(AdminStatusChangeReq statusChangeReq) {
        List<Long> ids = statusChangeReq.getIds();
        getValidatedRoleByIds(ids);
        return laRoleRepository.removeByIds(ids);
    }

    /**
     * 根据角色ID列表校验并查询角色信息
     *
     * @param ids 角色ID列表
     * @throws LinkUException 如果角色ID列表为空或未找到角色
     */
    private void getValidatedRoleByIds(List<Long> ids) {
        List<LARole> roles = laRoleRepository.listByIds(ids);
        if (CollectionUtils.isEmpty(roles)) {
            log.error("未找到角色信息，id列表: {}", ids);
            throw new LinkUException(ErrorMessageEnums.ROLE_INFO_NOT_EXISTS.getErrorCode(),
                    messageSource.getMessage(ErrorMessageEnums.ROLE_INFO_NOT_EXISTS.getErrorMsg(), null, LocaleContextHolder.getLocale()));
        }
    }

    /**
     * 保存或更新角色信息
     *
     * @param roleReq 角色请求对象
     * @return 操作结果
     */
    public Boolean roleInfoSaveOrUpdate(AdminRoleReq roleReq) {
        LARole laRole = RoleMapperConverter.INSTANCE.covertReqToRole(roleReq);
        Long tenantId = Long.valueOf(TenantContext.getTenantId());
        laRole.setTenantId(tenantId);

        return transactionTemplate.execute(status -> {
            try {
                if (laRole.getId() != null) {
                    LARole existingRole = laRoleRepository.getById(laRole.getId());
                    if (existingRole != null) {
                        laRole.setObjectVersionNumber(existingRole.getObjectVersionNumber());
                        laRoleRepository.updateById(laRole);
                        return true;
                    }
                }
                laRoleRepository.save(laRole);
                roleReq.setId(laRole.getId());
                return true;
            } catch (OptimisticLockingFailureException e) {
                status.setRollbackOnly();
                return false;
            } catch (Exception e) {
                status.setRollbackOnly();
                return false;
            }
        });
    }

    @Override
    public LARole queryDetail(Serializable id) {
        return laRoleRepository.getById(id);
    }
}
